package service

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	"strconv"
	"strings"
	"time"
	"zimuzu_cvn_web_api/config"
	"zimuzu_cvn_web_api/model"
	"zimuzu_cvn_web_api/pkg/drive/redis"
	. "zimuzu_cvn_web_api/pkg/e"
	"zimuzu_cvn_web_api/pkg/errno"
)

const CodeExpire = 15     //金至尊兑换码有效期
const OrderTypeJZZ = 1    //会员订单类型
const OrderPayExpire = 60 //订单支付有效时间

type cvntPrice struct {
	Status int    `json:"status"`
	Info   string `json:"info"`
	Data   struct {
		UsdPrice float64 `json:"usdPrice"`
		Prict    float64 `json:"prict"`
	} `json:"data"`
}

//获取生成金至尊码任务缓存键
//Auth:Xu
func GetGenCodeTaskCacheKey(key string) string {
	return "cvn:public:genCodeTask:" + key

}

//查询cvnt价格
func GetCvntPrice() (price, usdPrice float64, err error) {
	Log("info", "【查询cvnt价格】 ")
	urlStr := config.C.JapenUrl + "/v1/market/getCvntCnyPrice"
	cvntPrice := cvntPrice{}
	errInfo := "查询cvnt价格失败"
	if err := HttpGet(urlStr, &cvntPrice); err != nil {
		err = errors.New(errInfo)
		Log("err", errInfo, err.Error())
		return 0, 0, err
	}
	usdPrice = cvntPrice.Data.UsdPrice
	//如果请求价格的接口挂掉，   默认只展示CVNT的数量
	if usdPrice == 0 {
		usdPrice = 1
	}

	price = cvntPrice.Data.Prict
	if price == 0 {
		err = errors.New("查询CVNT价格出错")
	}
	return
}

type AgentInfoRes struct {
	Level         int                  `json:"level"`
	Status        int                  `json:"status"`
	Show          int                  `json:"Show"`
	Wechat        string               `json:"wechat,omitempty"`
	Email         string               `json:"email,omitempty"`
	RemainingTime int64                `json:"remainingTime"`
	GoodsList     []AgentInfoGoodsList `json:"goodsList"`
}

type AgentInfoGoodsList struct {
	Cvnt   int   `json:"cvnt"`
	Gid    int64 `json:"gid"`
	Period int   `json:"period"`
}

//获取经销商信息
func GetAgentInfo(uid int64) (res AgentInfoRes, err error) {

	info, err := model.GetAgentInfoByUid(uid)
	if err != nil {
		return
	}

	if info.Level == 0 {
		//非经销商
		agentDiscountList, err := model.GetAgentDiscount()
		if err != nil {
			return res, err
		}
		res.GoodsList = make([]AgentInfoGoodsList, len(agentDiscountList))
		for k, value := range agentDiscountList {
			res.GoodsList[k].Cvnt = FormatPrice(value.Price)
		}
	} else {
		res.Level = info.Level
		res.Show = info.Show
		res.Status = info.Status
		res.Wechat = info.Wechat
		res.Email = info.Email
		res.RemainingTime = (info.ExpireTime - time.Now().Unix()) / TimeFormatDay

		//当前cvnt对应人民币价格
		price, _, err := GetCvntPrice()
		if err != nil {
			return res, err
		}

		//经销商折扣
		agentType, err := model.GetAgentTypeInfoByLevel(info.TypeId)
		if err != nil {
			return res, err
		}

		//商品原价
		originPriceList, err := model.GetGoodsOriginPrice()
		if err != nil {
			return res, err
		}

		res.GoodsList = make([]AgentInfoGoodsList, len(originPriceList))
		for k, value := range originPriceList {
			//折扣
			goodsDiscount, _ := model.GetMaxDiscountByGid(value.Gid)
			res.GoodsList[k].Gid = value.Gid
			res.GoodsList[k].Cvnt = FormatPrice(value.OriginPriceRmb * agentType.Discount * goodsDiscount / price)
			res.GoodsList[k].Period = value.Period
		}
	}

	return
}

//查看经销商资料
type ViewAgentInfoRes struct {
	Wechat        string `json:"wechat" db:"wechat"`
	Email         string `json:"email" db:"email"`
	RemainingTime int    `json:"remainingTime" db:"remainingTime"`
}

func ViewAgentInfo(uid, agentUid int64) (info ViewAgentInfoRes, err error) {
	uidStr := strconv.FormatInt(uid, 10)
	agentStr := strconv.FormatInt(agentUid, 10)

	agentListKey := UserRedisPrefix + RedisUserViewAgentUidList + uidStr
	list, _ := redis.SMembers(agentListKey)
	isMember := redis.IsMember(agentListKey, agentStr)
	if len(list) >= 3 && !isMember && agentUid != uid {
		return info, errors.New("每天只可查看3个经销商的联系方式")
	}
	if !isMember && agentUid != uid {
		//添加uid到set
		_, _ = redis.SAdd(agentListKey, agentStr)

		if len(list) == 0 {
			//设置过期时间
			timeStr := time.Now().Format(TimeFormatD)
			t, _ := time.ParseInLocation(TimeFormatD, timeStr, time.Local)
			expireTime := t.AddDate(0, 0, 1).Unix()
			expireTime = expireTime - time.Now().Unix()
			_, _ = redis.Expire(agentListKey, int(expireTime))
		}
	}

	count, _ := redis.SCard(agentListKey)
	info.RemainingTime = 3 - count

	agentInfo, err := model.GetAgentInfoByUid(agentUid)
	if err != nil {
		return info, errors.New("查询经销商联系方式失败")
	}
	info.Wechat = agentInfo.Wechat
	info.Email = agentInfo.Email

	return
}

type PriceFormRes struct {
	Cvnt  float64       `json:"cvnt"`
	Price [][][]float64 `json:"price"`
}

//价格表(缓存一个小时)
func PriceForm() (res PriceFormRes, err error) {
	//当前cvnt对应人民币价格
	res.Cvnt, _, err = GetCvntPrice()
	if err != nil {
		return
	}

	key := PublicCacheKeyPre + "PriceForm"
	if redis.Exists(key) {
		redisData, err := redis.Get(key)
		if err != nil {
			Log("err", "PriceForm 读取 redis 数据失败", err.Error())
			return res, err
		}

		err = json.Unmarshal([]byte(redisData), &res.Price)
		if err != nil {
			Log("err", "PriceForm 解析 redis 数据失败", err.Error())
		}
		return res, err
	}

	//经销商折扣(id, level, discount，ORDER BY level)
	agentDiscountList, err := model.GetAgentDiscount()
	if err != nil {
		return
	}

	//套餐折扣(id, gid, num, discount， ORDER BY gid, num)
	packageDiscountList, err := model.GetPackageDiscountByGid()
	if err != nil {
		return
	}

	//商品原价(gid, period, origin_price_rmb， ORDER BY period)
	originPriceList, err := model.GetGoodsOriginPrice()
	if err != nil {
		return
	}

	res.Price = make([][][]float64, 0)
	for _, agentV := range agentDiscountList {
		var packageList = make([][]float64, 0)
		var priceList = make([]float64, 0)
		var gid = packageDiscountList[0].Gid

		for packageK, packageV := range packageDiscountList {
			var price float64
			//查找该套餐对应的原价
			for _, value := range originPriceList {
				if value.Gid == packageV.Gid {
					price = value.OriginPriceRmb
				}
			}

			if gid == packageV.Gid {
				//把相同gid的套餐放一起
				cvnt := price * packageV.Discount * agentV.Discount
				priceList = append(priceList, cvnt)
			} else {
				packageList = append(packageList, priceList)
				priceList = make([]float64, 0)

				cvnt := price * packageV.Discount * agentV.Discount
				priceList = append(priceList, cvnt)

				gid = packageV.Gid
			}

			if packageK == len(packageDiscountList)-1 {
				packageList = append(packageList, priceList)
			}
		}
		res.Price = append(res.Price, packageList)
	}

	//res 转 json 字符串存入 redis
	resStr, err := json.Marshal(res.Price)
	if err != nil {
		Log("info", "转 json 字符串失败", err.Error())
	} else {
		//更新缓存
		_, _ = redis.Set(key, resStr, TimeFormatHour)
	}

	return
}

//查询升价码信息
type UpgradeCodeInfo struct {
	model.UpgradeCodeTotalNum
	Sold struct {
		model.UpgradeCodeNum
	} `json:"sold"`
	Unsold struct {
		model.UpgradeCodeNum
	} `json:"unsold"`
}

func GetUpgradeCodeInfo(uid int64) (info UpgradeCodeInfo, err error) {
	info.UpgradeCodeTotalNum, err = model.GetUpgradeCodeTotalNum(uid)
	if err != nil {
		return
	}

	info.Sold.UpgradeCodeNum, err = model.GetUpgradeCodeNum(uid, 1)
	if err != nil {
		return
	}

	info.Unsold.UpgradeCodeNum, err = model.GetUpgradeCodeNum(uid, 0)
	if err != nil {
		return
	}

	return
}

//新人榜、品质榜
func AgentRank(page, per int, source int) (info []model.AgentRankInfo, err error) {
	key := PublicCacheKeyPre + "agentRank:source:" + strconv.Itoa(source) + ":page:" + strconv.Itoa(page) + ":per:" + strconv.Itoa(per)
	if redis.Exists(key) {
		redisData, err := redis.Get(key)
		if err != nil {
			Log("err", "读取 redis 数据失败", err.Error())
			return info, err
		}

		err = json.Unmarshal([]byte(redisData), &info)
		if err != nil {
			Log("err", "解析 redis 数据失败", err.Error())
		}
		return info, err
	}

	res, err := model.GetAgentRankList(page, per, source)
	if err != nil {
		return
	}

	for _, user := range res {
		//昵称隐藏
		user.Name = NicknameFormat(user.Name)
		info = append(info, user)
	}

	//res 转 json 字符串存入 redis
	resStr, err := json.Marshal(info)
	if err != nil {
		Log("info", "转 json 字符串失败", err.Error())
	} else {
		//更新缓存
		_, _ = redis.Set(key, resStr, TimeFormatMin)
	}

	return
}

//查询单个经销商套餐价格
//Auth： Xu
//func GetAgentPackagePrice(uid int64,packageID int)(float64, error){
//	info, err := CheckAgentInfo(uid)
//	if err != nil{
//		return 0, err
//	}
//
//}

type CurrentPackagePrice struct {
	PackageId  int64 `json:"packageId"`
	UnitPrice  int   `json:"unitPrice"`
	Num        int   `json:"num"`
	TotalPrice int   `json:"totalPrice"`
}

//查询商品的套餐信息
//Auth：Xu
func GetGoodsPackageList(uid int64, goodsId int) (packagePriceList []CurrentPackagePrice, err error) {
	packageList, err := model.GetPackageByGid(goodsId)
	if err != nil {
		err = errors.New("查询商品套餐信息失败")
		return
	}
	//经销商折扣(id, level, discount)
	agentDiscountInfo, err := model.GetAgentDiscountInfoByUid(uid)
	if err != nil {
		err = errors.New("查询经销商信息失败")
		return
	}
	//当前cvnt价格
	cvntPrice, _, err := GetCvntPrice()
	if err != nil {
		return
	}
	//商品原价
	goodsInfo, err := model.GetGoodsInfoByGid(int64(goodsId))
	if err != nil {
		err = errors.New("查询商品价格信息失败")
		return
	}
	var packagePriceInfo CurrentPackagePrice
	for _, packageInfo := range packageList {
		packagePriceInfo.PackageId = packageInfo.Id
		disconut := agentDiscountInfo.Discount * packageInfo.Discount
		packagePriceInfo.UnitPrice = convertGoodsExCVNT(goodsInfo.OriginPriceRmb, cvntPrice, disconut)
		packagePriceInfo.Num = packageInfo.Num
		packagePriceInfo.TotalPrice = packagePriceInfo.UnitPrice * packageInfo.Num
		packagePriceList = append(packagePriceList, packagePriceInfo)
	}
	return
}

//查询经销商身份信息
//Auth: Xu
func CheckAgentInfo(uid int64) (info model.AgentInfo, err error) {
	info, err = model.GetAgentInfoByUid(uid)
	if err != nil {
		err = errors.New("为查找到经销商信息")
	}

	return
}

//计算商品兑换所需的cvnt
//Auth: Xu
func convertGoodsExCVNT(originPriceRmb float64, cvntPrice float64, Discount float64) (cvntNum int) {
	return int(originPriceRmb * Discount / cvntPrice)
}

type OrderInfo struct {
	OrderNo    string  `json:"orderNo"`
	TotalPrice float64 `json:"totalPrice"`
	GoodsName  string  `json:"goodsName"`
	Num        int     `json:"num"`
	CreateTime string  `json:"createTime"`
	UnitPrice  int     `json:"unitPrice"`
	ExpireSec  int     `json:"expireSec"`
}

//经销商下单
//Auth: Xu
func ExchangeVip(uid int64, packageId int) (orderInfo OrderInfo, err error) {
	nxCacheKey := "cvn:ExchangeVip:" + strconv.FormatInt(uid, 10)
	res, err := redis.RedisSetnx(nxCacheKey, "1", 3)
	if err != nil || !res {
		err = errors.New("操作过于频繁，请稍后再试")
		return
	}

	packageInfo, err := model.GetPackageByid(packageId)
	if err != nil {
		err = errors.New("查询商品套餐信息失败")
		return
	}
	//经销商折扣(id, level, discount)
	agentDiscountInfo, err := model.GetAgentDiscountInfoByUid(uid)
	if err != nil {
		err = errors.New("查询经销商信息失败")
		return
	}
	//当前cvnt价格
	cvntPrice, _, err := GetCvntPrice()
	if err != nil {
		return
	}
	//商品原价
	goodsInfo, err := model.GetGoodsInfoByGid(packageInfo.Gid)
	if err != nil {
		err = errors.New("查询商品价格信息失败")
		return
	}
	//套餐价格
	unitPrice := convertGoodsExCVNT(goodsInfo.OriginPriceRmb, cvntPrice, agentDiscountInfo.Discount*packageInfo.Discount)
	packagePrice := unitPrice * packageInfo.Num

	conn := config.C.DB.DB
	////判断账户余额是否足够
	//userAmount, err := GetUserAmount(uid)
	//if err != nil {
	//	conn.Rollback()
	//	return
	//}
	//if userAmount.UnWithdrawnCvn - float64(packagePrice) < 0 {
	//	conn.Rollback()
	//	return errno.WalletNotEnoughERR
	//}

	order := model.AgentGoodsOrder{
		OrderNum:        genOrderNum(uid),
		Uid:             uid,
		Level:           agentDiscountInfo.Level,
		Gid:             packageInfo.Gid,
		PackageId:       packageInfo.Id,
		PayStatus:       model.OrderUnPay,
		GoodsName:       goodsInfo.Title,
		TotalGoodsNum:   packageInfo.Num,
		AgentDiscount:   agentDiscountInfo.Discount,
		PackageDiscount: packageInfo.Discount,
		OriginPriceRmb:  goodsInfo.OriginPriceRmb,
		TotalPrice:      float64(packagePrice),
		Rate:            cvntPrice,
		CreateTime:      time.Now().Unix(),
	}

	err = model.InsertGoodsOrder(conn, order)
	if err != nil {
		err = errors.New("生成订单失败")
		return
	}

	orderInfo = OrderInfo{
		OrderNo:    order.OrderNum,
		TotalPrice: order.TotalPrice,
		GoodsName:  goodsInfo.Title,
		Num:        packageInfo.Num,
		CreateTime: time.Now().Format("2006-01-02 15:04:05"),
		UnitPrice:  unitPrice,
		ExpireSec:  OrderPayExpire,
	}
	return
}

//兑换金至尊订单支付及生成兑换码
//Auth: Xu
func PayOrder(orderNo string, uid int64) (err error) {
	nxCacheKey := "cvn:PayOrder:" + strconv.FormatInt(uid, 10)
	res, err := redis.RedisSetnx(nxCacheKey, "1", 2)
	if err != nil || !res {
		return errors.New("操作过于频繁，请稍后再试")
	}

	orderInfo, err := model.GetGoodsOrderInfoByNo(config.C.DB.DB, orderNo)
	if err != nil {
		return errors.New("未查找到订单信息")
	}
	if time.Now().Unix()-orderInfo.CreateTime > 60 {
		return errors.New("超过订单有效支付时间，请重新下单")
	}
	if orderInfo.PayStatus == model.OrderPayed {
		return errors.New("订单已支付")
	}
	if orderInfo.Uid != uid {
		return errors.New("非法操作")
	}

	timeNowInt64 := time.Now().Unix()
	conn, _ := config.C.DB.DB.Beginx()
	//修改amount,插入cvn流水
	updateAmountData := UpdateCvnAmountParams{
		Uid:         uid,
		Amount:      -float64(orderInfo.TotalPrice),
		Source:      model.LogSourceExchangeVipCode,
		RelateId:    strconv.FormatInt(orderInfo.Id, 10),
		RelateTable: "agent_goods_order",
	}
	_, err = UpdateCvnAmountBalance(conn, updateAmountData)
	if err != nil {
		conn.Rollback()
		return
	}
	//修改支付状态
	err = model.UpdateGoodsOrderPayStatus(conn, timeNowInt64, orderNo)
	if err != nil {
		conn.Rollback()
		return errors.New("修改订单支付状态失败")
	}

	//异步,通知主站生成兑换码
	//goodsInfo, err := model.GetGoodsInfoByGid(orderInfo.Gid)
	//err = rrapi.CodeCreateOrder(uid, orderNo, orderInfo.TotalGoodsNum, goodsInfo.Period)
	//if err != nil {
	//	conn.Rollback()
	//	return err
	//}

	err = addGenVipCodeQueue(orderNo, orderInfo.TotalGoodsNum)
	if err != nil {
		conn.Rollback()
		return err
	}
	conn.Commit()

	return
}

//加入待生成队列
//Auth:Xu
func addGenVipCodeQueue(orderNo string, goodsNum int) (err error) {
	_, err = redis.SAdd(GenVipCodeSetCacheKey, orderNo)
	if err != nil {
		return errors.New("生成金至尊码失败")
	}
	taskCacheKey := GetGenCodeTaskCacheKey(orderNo)
	_, err = redis.Incrby(taskCacheKey, goodsNum)
	if err != nil {
		return errors.New("生成兑换码失败")
	}
	return
}

//删除金至尊兑换订单缓存
//Auth: Xu
func delAgendOrderCache(orderNo string) {
	redis.SRem(GenVipCodeSetCacheKey, orderNo)
	taskCacheKey := GetGenCodeTaskCacheKey(orderNo)
	redis.Delete(taskCacheKey)
}

//生成兑换金至尊订单号
//Auth:Xu
func genOrderNum(uid int64) string {
	currentTimeStr := time.Now().Format("2006-01-02")
	currentTimeStr = strings.Replace(currentTimeStr, "-", "", -1)
	timeStr := strconv.FormatInt(time.Now().Unix(), 10)[5:10]
	uidStr := strconv.FormatInt(uid, 10)
	return currentTimeStr + uidStr + timeStr
}

//执行生成金至尊兑换码的任务
//Auth:Xu
func GenVipCode() {
	task, res := redis.SMembers(GenVipCodeSetCacheKey)
	if res != true {
		return
	}
	for _, val := range task {
		go func(orderNo string) {
			//orderInfo, err := model.GetGoodsOrderInfoByNo(config.C.DB.DB, orderNo)
			//if err != nil {
			//	return
			//}
			//查询主站金至尊订单的信息
			//rrOrderInfo, err := rrapi.GetCodeOrderInfo(orderInfo.Uid, orderNo)
			//if err != nil {
			//	return
			//} else if rrOrderInfo.Status == 1 {
			//	delAgendOrderCache(orderNo)
			//	model.UpdateGoodsOrder(config.C.DB.DB, orderNo)
			//	return
			//}

			//orderInfo, err := model.GetGoodsOrderInfoByNo(config.C.DB.DB, orderNo)
			//if err != nil {
			//	return
			//}
			//goodsInfo, err := model.GetGoodsInfoByGid(orderInfo.Gid)
			//if err != nil {
			//	err = errors.New("查询商品价格信息失败")
			//	return
			//}
			//taskCacheKey := GetGenCodeTaskCacheKey(orderNo)
			//for i := 0; i < orderInfo.TotalGoodsNum; i++ {
			//	dealNum, _ := redis.Decr(taskCacheKey)
			//	if dealNum >= 0 {
			//		err = AddVipCode(orderInfo.Uid, goodsInfo.Period, orderNo, 1)
			//		if err != nil {
			//			continue
			//		}
			//	} else {
			//		break
			//	}
			//}
			//succNum, _ := model.GetCodeNumSuccByOrderNo(config.C.DB.DB, orderNo)
			//failNum := orderInfo.TotalGoodsNum - succNum
			//if failNum == 0 {
			//	delAgendOrderCache(orderNo)
			//	model.UpdateGoodsOrder(config.C.DB.DB, orderNo)
			//	return
			//} else {
			//	redis.Set(taskCacheKey, failNum, -1)
			//}

		}(val)
	}
}

//生成金至尊兑换码
//Auth: Xu
const GenCodeMaxGenTimes = 3 //最大重试次数
func AddVipCode(uid int64, period int, orderNo string, times int) (err error) {
	code := Krand(6, 3, time.Now().UnixNano())
	err = model.InsertUpgrade(config.C.DB.DB, uid, code, period, orderNo)
	times++
	if err != nil {
		if times <= GenCodeMaxGenTimes {
			AddVipCode(uid, period, orderNo, times)
		} else {
			Log("info", "生成金至尊兑换码失败")
			return errors.New("生成金至尊兑换码失败")
		}
	}
	return
}

type orderStruct struct {
	GoodsName  string `json:"goodsName"`
	OrderNo    string `json:"orderNo"`
	TotalPrice int    `json:"totalPrice"`
	Num        int    `json:"num"`
	CreateTime string `json:"createTime"`
	UnitPrice  int    `json:"unitPrice"`
	Level      int    `json:"level"`
}

// 查询金至尊兑换列表
//Auth: Xu
func GetGoodsOrderList(uid int64, date string) ([]orderStruct, error) {
	var orderList []orderStruct
	orderListDb, err := model.GetGoodsOrderList(uid, date)
	if err != nil {
		return orderList, err
	}
	for _, order := range orderListDb {
		createTime := time.Unix(order.CreateTime, 0)
		var orderNew orderStruct
		orderNew.Level = order.Level
		orderNew.GoodsName = order.GoodsName
		orderNew.OrderNo = order.OrderNum
		orderNew.TotalPrice = int(order.TotalPrice)
		orderNew.Num = order.TotalGoodsNum
		orderNew.CreateTime = createTime.Format("01") + "月" + createTime.Format("02") + "日" + " " + createTime.Format("15") + ":" + createTime.Format("04")
		orderNew.UnitPrice = orderNew.TotalPrice / orderNew.Num
		orderList = append(orderList, orderNew)
	}

	return orderList, err
}

// 申请成为经销商
// Auth:hzp
type AgentApplyResponse struct {
	ValidTime int `json:"valid_time" db:"valid_time"`
}

func AgentApply(uid int64, level int) (res AgentApplyResponse, err error) {

	// 校验是否在黑名单
	ok, err := model.IsBlackUser(config.C.DB.DB, uid)
	if err != nil {
		return res, errno.GetDataErr
	}
	if ok {
		return res, errno.BlackUser
	}
	// 校验商品数据信息
	agentInfo, err := model.GetAgentTypeInfoByLevel(int64(level))
	if err != nil {
		return res, err
	}
	if agentInfo.Price <= 0 {
		err = errno.FiledError
		return
	}
	typeId, err := model.GetTypeIdByTypeAndLevel(1, level)
	if err != nil {
		return
	}
	actionType := model.AgentActionRenew
	// 1、生成申请记录
	// 开启事务
	conn, err := config.C.DB.DB.Beginx()
	if err != nil {
		conn.Rollback()
		return
	}
	timeNowInt64 := time.Now().Unix()
	expireTime := timeNowInt64 + 3600*24*365
	// 校验是否已经是经销商
	agentUserInfo, err := model.GetAgentDiscountInfoByUid(uid)
	if err == sql.ErrNoRows {
		actionType = model.AgentActionApply
		agentUserData := model.AgentInfo{
			Uid:    uid,
			TypeId: typeId,
			Type:   model.AgentTypeVip,
			Level:  level,
		}
		_, err = model.InsertAgentUserInfo(conn, agentUserData)
		if err != nil {
			conn.Rollback()
			return
		}
	} else if err != nil {
		conn.Rollback()
		err = errors.New("查询经销商信息出错")
		return
	} else {
		//续费
		err = model.UpdateAgentGrade(conn, typeId, model.AgentTypeVip, level, expireTime, agentUserInfo.Id)
		if err != nil {
			conn.Rollback()
			err = errors.New("修改经销商等级出错")
			return
		}
	}
	// 2、并生日志记录
	agentUserLogData := model.AgentInfoLog{
		Uid:         uid,
		Type:        model.AgentTypeVip,
		BeforeLevel: agentUserInfo.Level,
		AfterLevel:  level,
		BeforeTime:  agentUserInfo.ExpireTime,
		AfterTime:   expireTime,
		Price:       agentInfo.Price,
		Action:      actionType,
	}
	logId, err := model.InsertAgentUserLog(conn, agentUserLogData)
	if err != nil {
		conn.Rollback()
		err = errors.New("插入升级日志出错")
		return
	}
	//修改amount,插入cvn流水
	updateAmountData := UpdateCvnAmountParams{
		Uid:         uid,
		Amount:      -agentInfo.Price,
		Source:      model.LogSourceBeAgent,
		RelateId:    strconv.FormatInt(logId, 10),
		RelateTable: "agent_user_log",
	}
	_, err = UpdateCvnAmountBalance(conn, updateAmountData)
	if err != nil {
		conn.Rollback()
		return
	}

	conn.Commit()

	res.ValidTime = 365

	// 申请完更新可升级列表
	cacheKey := UpgradeListForCache + strconv.FormatInt(uid, 10)
	redis.UnDelete(cacheKey)

	return
}

// 升级经销商
func AgentUpgrade(uid int64, fromLevel, toLevel int) (err error) {

	// 校验数据
	userInfo, err := model.GetAgentInfoByUid(uid)
	if err != nil {
		return err
	}

	if userInfo.Level != fromLevel {
		return errno.UserInfoErr
	}

	// 校验是否在黑名单
	ok, err := model.IsBlackUser(config.C.DB.DB, uid)
	if err != nil {
		return errno.GetDataErr
	}
	if ok {
		return errno.BlackUser
	}

	// 更新日志
	typeId, diffPrice, err := getDiffPrice(int64(fromLevel), int64(toLevel))
	if err != nil {
		return err
	}
	expireTime := (userInfo.ExpireTime - time.Now().Unix()) / int64(24*3600)
	cvn, _ := strconv.ParseFloat(fmt.Sprintf("%.0f", diffPrice/365*float64(expireTime)), 64)

	// 进行升级
	if cvn <= 0 {
		return errno.FiledError
	}
	// 开启事务
	conn, err := config.C.DB.DB.Beginx()
	if err != nil {
		return err
	}
	// 1、更新记录
	err = model.UpdateAgentGrade(conn, typeId, model.AgentTypeVip, toLevel, userInfo.ExpireTime, userInfo.Id)
	if err != nil {
		err = errors.New("修改经销商等级失败")
		return
	}

	// 2、并生日志记录
	agentUserLogData := model.AgentInfoLog{
		Uid:         uid,
		Type:        model.AgentTypeVip,
		BeforeLevel: fromLevel,
		AfterLevel:  toLevel,
		BeforeTime:  userInfo.ExpireTime,
		AfterTime:   userInfo.ExpireTime,
		Price:       cvn,
		Action:      model.AgentActionUpgrade,
	}
	logId, err := model.InsertAgentUserLog(conn, agentUserLogData)
	if err != nil {
		conn.Rollback()
		err = errors.New("插入升级日志出错")
		return
	}
	//修改amount,插入cvn流水
	updateAmountData := UpdateCvnAmountParams{
		Uid:         uid,
		Amount:      -cvn,
		Source:      model.LogSourceBeAgent,
		RelateId:    strconv.FormatInt(logId, 10),
		RelateTable: "agent_user_log",
	}
	_, err = UpdateCvnAmountBalance(conn, updateAmountData)
	if err != nil {
		conn.Rollback()
		return
	}

	conn.Commit()

	// 升级完更新可升级列表
	cacheKey := UpgradeListForCache + strconv.FormatInt(uid, 10)
	redis.UnDelete(cacheKey)
	return nil
}

// 经销商可升级列表
// Auth:hzp
type UpgradeData struct {
	Type  int64   `json:"type"`
	Title string  `json:"title"`
	Price float64 `json:"price"`
}
type UpgradeUserData struct {
	Type   int64   `json:"type"`
	Title  string  `json:"title"`
	Price  float64 `json:"price"`
	Expire int64   `json:"expire"`
}
type UpgradeList struct {
	User    UpgradeUserData
	Upgrade []UpgradeData
}

func GetAgentUpgradeList(uid int64) (list UpgradeList, err error) {

	cacheKey := UpgradeListForCache + strconv.FormatInt(uid, 10)
	redis.UnDelete(cacheKey)

	if redis.Exists(cacheKey) {
		reData, err := redis.Get(cacheKey)
		if err != nil {
			return list, err
		}
		err = json.Unmarshal([]byte(reData), &list)
		if err != nil {
			return list, err
		}
		return list, nil
	}

	// 校验是否在黑名单
	ok, err := model.IsBlackUser(config.C.DB.DB, uid)
	if err != nil {
		return list, errno.GetDataErr
	}
	if ok {
		return list, errno.BlackUser
	}

	// 获取到经销商信息
	agentInfo, err := model.GetAgentInfoByUid(uid)
	if err != nil && err != errno.RecordError {
		return list, err
	}

	// 获取到类型数据
	agentDiscountList, err := model.GetAgentDiscount()
	if err != nil {
		return list, err
	}

	var currentPrice float64
	for _, k := range agentDiscountList {
		if agentInfo.Uid == 0 {
			var ll UpgradeData
			ll.Type = k.Id
			ll.Title = k.Title
			ll.Price = k.Price
			list.Upgrade = append(list.Upgrade, ll)
		} else {
			if k.Level > agentInfo.Level {
				var ll UpgradeData
				ll.Type = k.Id
				ll.Title = k.Title
				ll.Price = k.Price
				list.Upgrade = append(list.Upgrade, ll)
			} else if k.Level == agentInfo.Level {
				list.User.Type = k.Id
				list.User.Title = k.Title
				list.User.Price = k.Price
				currentPrice = k.Price
			}
		}
	}

	var expireTime int64
	if agentInfo.ExpireTime == 0 {
		expireTime = 365
	} else {
		if agentInfo.ExpireTime <= time.Now().Unix() {
			expireTime = 0
		} else {
			expireTime = (agentInfo.ExpireTime - time.Now().Unix()) / int64(24*3600)
		}
	}
	for v, k := range list.Upgrade {
		list.Upgrade[v].Price, _ = strconv.ParseFloat(fmt.Sprintf("%.0f", (k.Price-currentPrice)/365*float64(expireTime)), 64)
	}

	list.User.Expire = expireTime
	reStr, _ := json.Marshal(list)
	redis.SetUnRe(cacheKey, string(reStr), TimeFormatHour)
	return list, nil
}

// 获取升级差价
// Auth:hzp
func getDiffPrice(beforeType, afterType int64) (afterId int64, diff float64, err error) {

	agentDiscountList, err := model.GetAgentDiscount()
	if err != nil {
		return afterId, diff, err
	}
	var beforePrice, afterPrice float64
	var findBefore, findAfter, beforeLevel, afterLevel int
	for _, k := range agentDiscountList {
		if k.Id == beforeType {
			findBefore = 1
			beforeLevel = k.Level
			beforePrice = k.Price
		}
		if k.Id == afterType {
			afterId = k.Id
			findAfter = 1
			afterLevel = k.Level
			afterPrice = k.Price
		}
	}

	if afterLevel <= beforeLevel {
		return afterId, diff, errno.ParamsError
	}

	if findAfter != 1 || findBefore != 1 {
		return afterId, diff, errno.ParamsError
	}
	diff = afterPrice - beforePrice
	return afterId, diff, nil
}

// 将过期的经销商更新为 2-已到期
func ExpireAgent() {
	err := model.UpdateExpiredAgent(config.C.DB.DB)
	if err != nil {
		Log("err", "err:", err)
	}
	return
}
